package com.qkjia.asyncfilechannel;

import org.junit.Test;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
 * 异步文件通道
 */
public class AsyncFileChannelDemo {


    /**
     * 写异步文件 Complate 01
     * @throws IOException 异常
     */
    @Test
    public void writeAsyncFileComplate() throws IOException {
        // 1  创建AsynchronousFileChannel
        // Path 可用于在文件系统中定位文件的对象。 它通常表示系统相关文件路径。
        Path path = Paths.get("e:\\qkjia\\002.txt");
        // .open(打开或创建用于读取和/或写入的文件，返回一个异步文件通道以访问该文件。
        // . StandardOpenOption.WRITE 打开以进行写访问。
        AsynchronousFileChannel fileChannel =
                AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

        //2 创建Buffer 分配一个新的字节缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        //3 write方法
        buffer.put("qkjiajavajava".getBytes());
        buffer.flip();

        fileChannel.write(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                System.out.println("bytes written: " + result);
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {

            }
        });

        System.out.println("write over");
    }

    /**
     * 写异步文件未来 02
     * @throws IOException 异常
     */
    @Test
    public void writeAsyncFileFuture() throws IOException {
        // 1 创建AsynchronousFileChannel
        // Path 可用于在文件系统中定位文件的对象。 它通常表示系统相关文件路径。
        Path path = Paths.get("e:\\qkjia\\002.txt");
        // .open(打开或创建用于读取和/或写入的文件，返回一个异步文件通道以访问该文件。
        // . StandardOpenOption.WRITE 打开以进行写访问。
        AsynchronousFileChannel fileChannel =
                AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

        // 2 创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 3 write方法
        buffer.put("qkjia ".getBytes());
        // 翻转这个缓冲区
        buffer.flip();
        Future<Integer> future = fileChannel.write(buffer, 0);

        // 如果此任务完成，则返回true 。 完成可能是由于正常终止、异常或取消——在所有这些情况下，此方法将返回true 。
        while(!future.isDone());

        buffer.clear();
        System.out.println("write over");
    }

    /**
     * 读取异步文件通道完成 03
     * @throws Exception 异常
     */
    @Test
    public void readAsyncFileChannelComplate() throws Exception {
        //1 创建AsynchronousFileChannel
        // Path 可用于在文件系统中定位文件的对象。 它通常表示系统相关文件路径。
        Path path = Paths.get("e:\\qkjia\\002.txt");
        // .open(打开或创建用于读取和/或写入的文件，返回一个异步文件通道以访问该文件。
        // . StandardOpenOption.WRITE 打开以进行写访问。
        AsynchronousFileChannel fileChannel =
                AsynchronousFileChannel.open(path, StandardOpenOption.READ);

        //2 创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        //3 调用channel的read方法得到Future
        fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                System.out.println("result: "+result);

                // 翻转这个缓冲区
                attachment.flip();
                byte[] data = new byte[attachment.limit()];
                //                相对批量获取方法。
                attachment.get(data);
                System.out.println(new String(data));
                attachment.clear();
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {

            }
        });
    }


    /**
     * 读取异步文件通道未来 04
     * @throws Exception
     */
    @Test
    public void readAsyncFileChannelFuture() throws Exception {
        //1 创建AsynchronousFileChannel
        Path path = Paths.get("e:\\qkjia\\002.txt");
        AsynchronousFileChannel fileChannel =
                AsynchronousFileChannel.open(path, StandardOpenOption.READ);

        //2 创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        //3 调用channel的read方法得到Future
        Future<Integer> future = fileChannel.read(buffer, 0);

        //4 判断是否完成 isDone,返回true
        while(!future.isDone());

        //5 读取数据到buffer里面
        buffer.flip();
//        while(buffer.remaining()>0) {
//            System.out.println(buffer.get());
//        }
        byte[] data = new byte[buffer.limit()];
        // get(data); 相对批量获取方法
        buffer.get(data);
        System.out.println(new String(data));
        buffer.clear();

    }


}
